<template>
  <div :class="['uploader',paste?'paste':'',paste && isFocus?'pasteFocus':'']" ref="container" :title="paste?'粘贴上传':''"
       @paste="onPaste" @focus="onFocus" @blur="onBlur" tabindex="-1">
    <!--file-->
    <FilePreview v-model:value="files" v-if="type =='file' && !onlyShow"></FilePreview>
    <div class="file-upload">
      <a-popover v-if="type == 'image' && input">
        <template #content>
          <ImagePreview v-model:value="files"></ImagePreview>
        </template>
        <a-input v-model:value="inputValue" :disabled="disabled" @blur="changeInput"
                 @pressEnter="changeInput" allowClear></a-input>
      </a-popover>
      <a-input v-else v-model:value="inputValue" :disabled="disabled" v-if="input" @blur="changeInput"
               @pressEnter="changeInput" allowClear></a-input>
      <span ref="element" v-if="type =='file' || input"  >
         <slot>
           <a-space v-show="(multiple && (limit==0 || files.length < limit)) || files.length == 0 || onlyShow">
             <a-button>
                <template #icon><cloud-upload-outlined/></template>
                {{ trans('Uploader.upload') }}
            </a-button>
            <a-button @click.stop="visible = true" v-if="!hideFinder && finder">
                 <template #icon><i class="far fa-folder-open"/></template>
            </a-button>
           </a-space>
         </slot>
      </span>
    </div>
    <template v-if="(type =='file' || input) && !progress">
      <a-progress v-show="percent > 0" status="active" :percent="percent"></a-progress>
      <div v-show="percent > 0">{{ progressText }}</div>
    </template>


    <!--image-->
    <div class="file-list" v-if="type == 'image' && !input">
      <ImagePreview v-model:value="files"></ImagePreview>
      <span ref="element" v-show="(multiple && (limit==0 || files.length < limit)) || files.length == 0">
        <slot>
          <div class="image-btn" :style="{height: imageHeight+'px',width:imageWidth+'px'}">
              <a-progress type="circle" v-show="percent > 0" :percent="percent" :width="imageHeight">
                  <template #format="percent">
                    <div>{{ percent }}%</div>
                    <div style="font-size: 12px">{{ progressText }}</div>
                  </template>
              </a-progress>
              <a-space direction="vertical">
                  <i class="fas fa-plus"/>
                  <i class="far fa-folder-open" v-if="!hideFinder && finder" @click.stop="visible = true"/>
              </a-space>
          </div>
        </slot>
      </span>
    </div>
    <a-modal v-model:visible="visible" width="70%" :title="trans('Uploader.finder')" @ok="visible=false">
      <a-form-item-rest>
        <render :data="finder" v-model:selection="files" :selection-limit="limit"
                :selection-type="multiple ? 'checkbox':'radio'" :scroll="height"></render>
      </a-form-item-rest>
    </a-modal>
  </div>
</template>
<script>
export default {
  name: 'ExUploader'
}
</script>
<script setup>
import ImagePreview from './ImagePreview.vue'
import FilePreview from './FilePreview.vue'
import {trans} from '@/utils'
import useUploader from '@/hook/uploader'
import {ref, watch, useAttrs, nextTick, onBeforeUnmount, onBeforeUpdate} from "vue";
import {message} from 'ant-design-vue';

const height = {
  x: 'max-content',
  y: window.innerHeight / 2
}
const attrs = useAttrs()

const props = defineProps({
  value: [String, Array],
  finder: [Boolean, Object],
  //请求url
  action: String,
  //uploader选项参数
  options: {
    type: Object,
    default: {}
  },
  imageWidth: {
    type: Number,
    default: 80
  },
  imageHeight: {
    type: Number,
    default: 80
  },
  type: {
    type: String,
    default: 'file'
  },
  //附加请求参数
  params: {
    type: Object,
    default: {}
  },
  headers: {
    type: Object,
    default: {}
  },
  disk: {
    type: String,
    default: 'local'
  },
  driver: {
    type: String,
    default: 'local'
  },
  //保存目录
  directory: {
    type: String,
    default: ''
  },
  hideFinder: {
    type: Boolean,
    default: false
  },
  //是否开启分片
  chunk: {
    type: Boolean,
    default: true
  },
  //分片大小MB为单位
  chunkSize: {
    type: Number,
    default: 1
  },
  //显示输入框
  input: {
    type: Boolean,
    default: false
  },
  //限制上传数量
  limit: {
    type: Number,
    default: 0
  },
  //禁用
  disabled: {
    type: Boolean,
    default: false
  },
  //是否支持多选文件
  multiple: {
    type: Boolean,
    default: false
  },
  paste: {
    type: Boolean,
    default: false
  },
  progress: {
    type: Boolean,
    default: true
  },
  saveFinder: {
    type: Boolean,
    default: true
  },
  onlyShow: {
    type: Boolean,
    default: true
  },
  //支持上传文件夹
  isDirectory: {
    type: Boolean,
    default: false
  },
  accept: {
    type: String,
    default: '*'
  },
  ext: {
    type: Array,
    default: []
  },
  fileSize: {
    type: Number,
    default: 0
  },
  domain: {
    type: String,
    default: ''
  },
  accessKey: {
    type: String,
    default: ''
  },
  secretKey: {
    type: String,
    default: ''
  },
  bucket: {
    type: String,
    default: ''
  },
  region: {
    type: String,
    default: ''
  },
  uploadToken: String,
})

const emit = defineEmits(['update:value', 'success', 'error', 'progress', 'fileSubmit', 'addFile'])
const container = ref()
const element = ref()
const visible = ref(false)
const percent = ref(0)
const files = ref([])
const inputValue = ref('')
const progressText = ref('')
const isFocus = ref(false)

watch(() => props.value, value => {
  setValue(value)
})

watch(files, value => {
  if (props.limit > 0 && value.length > props.limit) {
    files.value = files.value.slice(0, props.limit)
  }
  inputValue.value = value.join('|')
  if (props.multiple) {
    emit('update:value', value)
  } else {
    emit('update:value', inputValue.value)
  }
}, {deep: true})
setValue(props.multiple ? [...props.value]:props.value)

//失去焦点
function onBlur(e) {
  isFocus.value = false
}

//活动焦点
function onFocus(e) {
  isFocus.value = true
}

//粘贴
function onPaste(e) {
  if (isFocus.value) {
    e = e.originalEvent || e;
    let items, item, i, len, file
    items = e.clipboardData.items;
    for (i = 0, len = items.length; i < len; i++) {
      item = items[i];

      if (item.kind !== 'file' || !(file = item.getAsFile())) {
        continue;
      }
      upload.uploader.addFile(file)
    }
  }
}

function setValue(value) {
  if (props.multiple) {
    files.value = value
  } else {
    if (value) {
      files.value = [value]
    } else {
      files.value = []
    }
  }
}

let upload = null
watch(() => props.params, value => {
  upload.options.params = value
})

onBeforeUnmount(() => {
  upload.uploader.cancel()
  upload = null
})
uploadInit()

function uploadInit() {
  nextTick(() => {

    upload = useUploader(props)
    upload.input(element.value)
    upload.watch({
      addFile: (file, e) => {
        emit('addFile', file, e)
        if (props.ext.length > 0 && props.ext.indexOf(file.getExtension()) === -1) {
          message.error('只允许上传类型格式 ' + props.ext.join(','))
          return false
        }
        if (props.fileSize > 0 && file.size > props.fileSize) {
          message.error('上传文件超出限制大小' + attrs.fileSizeText)
          return false
        }
      },
      fileSubmit: fileArr => {
        emit('fileSubmit', fileArr)
        if (props.multiple && props.limit > 0 && (fileArr.length + files.value.length) > props.limit) {
          message.error('最大允许上传' + props.limit + '个文件')
          return false
        }
      },
      success: file => {

        emit('success', file)
        if (!props.multiple) {
          files.value = []
        }
        files.value.push(file)
        percent.value = 0
      },
      verifyProgress: percentage => {
        progressText.value = '校验中'
        percent.value = percentage
      },
      progress: percentage => {
        emit('progress', percentage)
        progressText.value = '上传中'
        percent.value = percentage
      },
      error: message => {
        emit('error', message)
      }
    })

  })
}

function changeInput(val) {
  files.value = inputValue.value.split('|')
  files.value = files.value.filter(function (s) {
    return s && s.trim()
  })
}
</script>

<style scoped lang="scss">
.image-btn {
  background-color: #fbfdff;
  border: 1px dashed #c0ccda;
  border-radius: 5px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;

  .fa-folder-open {
    display: none;

    &:hover {
      color: #2d8cf0;
    }
  }
}

.dark-theme {
  .image-btn {
    background: #1f1f1f;
  }
}

.image-tool {
  position: absolute;
  width: 100%;
  height: 25px;
  cursor: pointer;
  left: 0;
  top: 0;
  z-index: 1;
  text-align: center;
  line-height: 25px;
  color: #fff;
  background-color: rgba(0, 0, 0, .5);
  border-radius: 5%;
  transition: opacity .3s;
  display: none;
}

.image-btn:hover {
  border: 1px dashed #2d8cf0;

  i {
    display: block;
  }
}

.file-upload {
  display: flex;

}

.file-list {
  display: flex;
  align-items: center;

}

.uploader {
  display: inline-block;
}

.uploader + .uploader {
  margin-left: 8px;
}

.paste {
  padding: 10px;
  border-radius: 5px;
  border: 2px dashed #f0f0f0;
}

.pasteFocus {
  border-color: #2d8cf0;
  z-index: 1;
}
</style>
